<template>
	<div class="bluePrint">
		<div class="head">
			<div class="head_compList">
				<!-- :class="{ 'head_btn--active': contain.menuShow }"
                    @click="handleFlag('menuShow')" -->
				<!-- <div class="head_btn">
                    <el-tooltip effect="dark" content="图层" placement="top">
                        <i class="el-icon-s-operation"></i>
                    </el-tooltip>
                </div> -->
				<div class="head_btn" @click="saveJson">
					<el-tooltip effect="dark" content="保存" placement="top">
						<i class="iconfont icon-build"></i>
					</el-tooltip>
				</div>
				<div class="head_btn" @click="clearJson">
					<el-tooltip effect="dark" content="清空" placement="top">
						<i class="el-icon-delete"></i>
					</el-tooltip>
				</div>
			</div>
			<div class="head_blueInfo">
				<span v-if="contain.config">{{ contain.config.name }}</span>
				<div class="head_btn" @click="handleBuild">
					<el-tooltip effect="dark" content="组件编辑器" placement="top">
						<i class="el-icon-set-up"></i>
					</el-tooltip>
				</div>
			</div>
		</div>
		<div class="wrap">
			<div class="compList">
				<div class="title">导入节点</div>
				<draggable :group="{ name: 'form' }" ghost-class="ghost" :list="contain.component" :animation="300" class="layerMenu">
					<div v-for="(item, index) in contain.component" :key="index">
						<!-- 单列 -->
						<div
							v-contextmenu="{
								id: contain.menuId,
								event: contain.handleContextMenu,
								value: item
							}"
							@click="handleSetActive(item)"
							:class="[
								'menu__item',
								{
									'is-over': contain.overactive === item.index,
									'is-click': true === item.isClick
								}
							]"
							@mouseover="handleMouseover(item)"
							@mouseout="handleMouseout()"
						>
							<span class="menu__icon">
								<i :class="'iconfont ' + item.icon"></i>
							</span>
							<span class="menu__name" :title="item.name">{{ item.name }}</span>
						</div>
					</div>
				</draggable>
			</div>
			<div class="compList logicNode">
				<div class="title">逻辑节点</div>
				<div class="content">
					<div class="subTitle">全局节点（{{ logicNodes.globalNodes.length }}）</div>
					<div
						@click="handleLogicNode(item)"
						class="menu__item blue"
						:class="{
							disabled: item.disabled
						}"
						v-for="(item, index) in logicNodes.globalNodes"
						:key="index"
					>
						<span class="menu__icon">
							<i :class="'el-icon-' + item.icon"></i>
						</span>
						<span class="menu__name" :title="item.name">{{ item.name }}</span>
					</div>

					<div class="subTitle">流程控制（{{ logicNodes.flowNodes.length }}）</div>
					<div
						@click="handleLogicNode(item)"
						class="menu__item orange"
						:class="{
							disabled: item.disabled
						}"
						v-for="(item, index) in logicNodes.flowNodes"
						:key="index"
					>
						<span class="menu__icon">
							<i :class="'el-icon-' + item.icon"></i>
						</span>
						<span class="menu__name" :title="item.name">{{ item.name }}</span>
					</div>

					<div class="subTitle">数据处理（{{ logicNodes.dataProcesNodes.length }}）</div>
					<div
						@click="handleLogicNode(item)"
						class="menu__item green"
						:class="{
							disabled: item.disabled
						}"
						v-for="(item, index) in logicNodes.dataProcesNodes"
						:key="index"
					>
						<span class="menu__icon">
							<i :class="'el-icon-' + item.icon"></i>
						</span>
						<span class="menu__name" :title="item.name">{{ item.name }}</span>
					</div>

					<div class="subTitle">输入设备（{{ logicNodes.inputEquipmentNodes.length }}）</div>
					<div
						@click="handleLogicNode(item)"
						class="menu__item purple"
						:class="{
							disabled: item.disabled
						}"
						v-for="(item, index) in logicNodes.inputEquipmentNodes"
						:key="index"
					>
						<span class="menu__icon">
							<i :class="'el-icon-' + item.icon"></i>
						</span>
						<span class="menu__name" :title="item.name">{{ item.name }}</span>
					</div>
				</div>
			</div>
			<div class="graph">
				<div class="title">
					<span> 缩放比例：</span>
					<el-slider v-model="scale" :step="0.1" :min="0" :max="3" show-input input-size="mini" @input="changeZoom"> </el-slider>
				</div>
				<div id="container"></div>
				<div id="miniMap"></div>
			</div>
			<div class="configLayer">
				<div class="title">
					配置面板
					<span v-if="topComp.name">({{ topComp.name }})</span>
				</div>
				<div class="content" v-if="topComp.name">
					<!-- <div v-for="(item, index) in topComp.eventConfig" :key="index">{{ item }}111</div> -->
					<div class="item">上游组件事件说明</div>
					<el-row :gutter="20">
						<el-col :span="12">
							<avue-select placeholder="选择事件" size="mini" :disabled="true" v-model="topComp.eventName" :dic="topComp.eventNamesList"> </avue-select>
						</el-col>
						<el-col :span="12">
							<avue-select size="mini" v-model="topComp.eventType" :dic="eventTypeData"> </avue-select>
						</el-col>
					</el-row>
					<div class="item">下游组件动作说明</div>
					<el-row :gutter="20">
						<el-col :span="12">
							<avue-input size="mini" :disabled="true" v-model="nextComp.name" />
						</el-col>
						<el-col :span="12">
							<avue-select placeholder="选择动作" size="mini" :disabled="true" v-model="nextComp.actionName" :dic="nextComp.actionList"> </avue-select>
						</el-col>
					</el-row>
					<div class="item">其他配置</div>
					<!-- 链接地址 -->
					<div v-if="topComp.eventType == '2'">
						<avue-input size="mini" :disabled="true" v-model="topComp.linkUrl" />
					</div>
					<!-- 自定义函数 -->
					<div v-if="topComp.eventType == '4'">
						<avue-input size="mini" :disabled="true" v-model="topComp.customFn" />
					</div>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
import { Graph, Edge, Shape, NodeView } from '@antv/x6';
import { GridLayout } from '@antv/layout';
import { mapState, mapGetters } from 'vuex';
import { getObj } from '@/api/visual';
import { logicNodes, renderLogicNodeGraph } from '@/page/bluePrint/logicNodes';
export default {
	name: 'bluePrint',
	components: {},
	data() {
		return {
			topComp: {
				eventName: '',
				eventType: '',
				linkUrl: '',
				customFn: ''
			},
			nextComp: {
				name: '',
				actionName: '',
				actionList: []
			},
			graph: null,
			target: null,
			contain: {
				overactive: '',
				config: {},
				component: []
			},
			scale: 1,
			logicNodes,
			baseActionList: [
				{
					label: '显示',
					value: 'show'
				},
				{
					label: '隐藏',
					value: 'hide'
				},
				{
					label: '请求数据',
					value: 'ajax'
				}
			],
			eventTypeData: [
				{ label: '控制显隐', value: '1' },
				{ label: '打开链接', value: '2' },
				{ label: '触发回调', value: '3' },
				{ label: '自定义函数', value: '4' }
			]
		};
	},
	computed: {
		...mapState({
			activeComps: state => state.activeComps,
			compsList: state => state.compsList
		}),
		...mapGetters(['activeCompsIndex'])
	},
	created() {
		this.initData();
	},
	mounted() {
		const that = this;
		let screenWidth = window.innerWidth;
		let screenHeight = window.innerHeight;
		that.graph = new Graph({
			container: document.getElementById('container'),
			autoResize: true,
			width: screenWidth - 760,
			height: screenHeight - 40,
			background: {
				color: '#2a2d32' // 设置画布背景颜色
			},
			grid: {
				size: 20, // 网格大小 10px
				visible: true // 渲染网格背景
			},
			selecting: true,
			snapline: {
				enabled: true
			},
			panning: {
				enabled: true,
				modifiers: 'shift'
			},
			// 高亮
			highlighting: {
				magnetAvailable: {
					name: 'stroke',
					args: {
						attrs: {
							fill: '#fff',
							stroke: '#ff8637'
						}
					}
				},
				magnetAdsorbed: {
					name: 'stroke',
					args: {
						attrs: {
							fill: '#fff',
							stroke: '#ff8637'
						}
					}
				}
			},
			connecting: {
				snap: true,
				allowBlank: false,
				allowLoop: false,
				highlight: true,
				connector: 'rounded',
				connectionPoint: 'boundary',
				createEdge() {
					return new Shape.Edge({
						attrs: {
							line: {
								stroke: '#A2B1C3',
								strokeWidth: 1,
								targetMarker: {
									name: 'classic',
									size: 7
								}
							}
						}
					});
				},
				validateConnection({ sourceView, targetView, targetMagnet }) {
					if (!targetMagnet) {
						return false;
					}
					if (targetMagnet.getAttribute('port-group') !== 'in') {
						return false;
					}
					return true;
				}
			},
			minimap: {
				enabled: true,
				container: document.getElementById('miniMap')
			},
			history: {
				enabled: true
			},
			keyboard: {
				enabled: true,
				global: true
			},
			resizing: {
				enabled: true,
				minWidth: 400,
				minHeight: 0,
				maxWidth: 9000,
				maxHeight: 9000,
				orthogonal: true,
				restricted: false,
				autoScroll: true,
				preserveAspectRatio: false,
				allowReverse: true
			},
			scroller: {
				enabled: true,
				pannable: true,
				pageVisible: true,
				pageBreak: false
			},
			mousewheel: {
				enabled: true,
				modifiers: ['ctrl', 'meta']
			}
		});

		that.renderJson(localStorage.getItem('dvp-lt-json'));

		that.resizeGraph();

		// 点击节点 - 获取信息
		that.graph.on('node:selected', ({ cell, node, options }) => {
			// console.log('node.nodeType', node);
			if (node.attrs.nodeType) {
				//逻辑节点
				that.handleLogicComputerNode(node);
			} else {
				// 组件节点
				that.handleClickNode(node.id);
			}
		});

		// 节点删除
		that.graph.on('node:removed', ({ node, index, options }) => {
			let findComp = that.contain.component.find(comp => comp.index == node.attrs.compId);
			that.$set(findComp, 'isClick', false);
		});

		// 增加连线
		that.graph.on('edge:connected', ({ isNew, edge }) => {
			if (isNew) {
				this.handleClearConfigLayerData();
				const sourceId = edge.getSourceCellId(); // 对新创建的边进行插入数据库等持久化操作
				const targetId = edge.getTargetCellId(); // 对新创建的边进行插入数据库等持久化操作
				let sourceNodeIndex = edge.getSource().port.replace(/[^\d]/g, '') - 1;
				let targetNodeIndex = edge.getTarget().port.replace(/[^\d]/g, '') - 1;

				let { currentComp: topComp } = this.getCurrentComp(sourceId);
				this.topComp = topComp;
				let { currentComp: nextComp } = this.getCurrentComp(targetId);
				this.nextComp = nextComp;
				this.topComp.eventName = this.topComp.eventNames[sourceNodeIndex];
				this.topComp.eventType = '3';
				console.log('this.topComp', this.topComp, this.nextComp);
				function handleActionList(data) {
					return data.map(item => {
						return {
							label: item.actionName,
							value: item.fnName
						};
					});
				}
				if (this.nextComp.actionConfig && this.nextComp.actionConfig.length > 0) {
					this.nextComp.actionList = [...this.baseActionList, ...handleActionList(this.nextComp.actionConfig)];
				} else {
					this.nextComp.actionList = this.baseActionList;
				}

				let targetActionModel = this.nextComp.actionList[targetNodeIndex].value;
				this.$set(this.nextComp, 'actionName', targetActionModel);
			}
		});

		// 删除连线
		that.graph.on('edge:removed', ({ edge, index, options }) => {
			console.log('删除连线', edge);
		});
	},
	beforeDestroy() {
		this.graph.dispose();
		this.graph = null;
	},
	methods: {
		// 获取当前组件，当前节点信息
		getCurrentComp(id) {
			let currentComp = null;
			let nowAllNodesInfo = this.graph.toJSON();
			let currentNode = nowAllNodesInfo.cells.filter(c => c.id == id);
			let shapeNodes = nowAllNodesInfo.cells.filter(c => c.shape == 'edge');
			// 来源
			let sourceShapeNodes = shapeNodes.filter(node => node.source.cell == id).map(n => n.id);
			// 目标
			let targetShapeNodes = shapeNodes.filter(node => node.target.cell == id).map(n => n.id);
			if (currentNode && currentNode[0].index) {
				currentComp = this.contain.component.find(c => c.index == currentNode[0].index);
			}
			return {
				currentComp
			};
		},
		handleClearConfigLayerData() {
			this.topComp.eventName = '';
			this.topComp.eventType = '';
			this.topComp.linkUrl = '';
			this.topComp.customFn = '';
			this.topComp.eventNamesList = [];
			this.nextComp.actionName = '';
			this.nextComp.actionList = [];
		},
		handleLogicComputerNode(node) {
			let nodeType = node.attrs.nodeType;
			switch (nodeType) {
				case 7:
					// 串行数据处理
					break;

				default:
					break;
			}
		},
		handleClickNode(id) {
			this.handleClearConfigLayerData();
			let { currentComp: topComp } = this.getCurrentComp(id);
			this.topComp = topComp;
			if (this.topComp && this.topComp.eventNames) {
				this.topComp.eventNamesList = this.topComp.eventNames.map(e => {
					return {
						label: e,
						value: e
					};
				});
			}
			// 设置当前组件事件
			// if (this.topComp.eventConfig && this.topComp.eventConfig.length > 0) {
			// 	this.topComp.eventName = this.topComp.eventConfig[0].eventName;
			// 	this.topComp.eventType = this.topComp.eventConfig[0].eventType;
			// }
		},
		resizeGraph() {
			window.addEventListener('resize', () => {
				let screenWidth = window.innerWidth;
				let screenHeight = window.innerHeight;
				this.graph && this.graph.resize(screenWidth - 600, screenHeight - 40);
			});
		},
		//初始化数据
		initData() {
			const id = this.$route.params.id;
			if (id) {
				const loading = this.$loading({
					lock: true,
					text: '正在加载中，请稍后',
					spinner: 'el-icon-loading',
					background: 'rgba(0, 0, 0, 0.7)'
				});
				// this.contain.component = JSON.parse(
				//     localStorage.getItem("dvp-lt-compList") || "[]"
				// );
				// this.contain.config.name = this.$route.query.title;
				getObj(id)
					.then(res => {
						const data = res.data.data;
						// this.contain.obj = data;
						let config = data.config;
						this.contain = {
							config: JSON.parse(config.detail) || {},
							component: JSON.parse(config.component) || []
						};
						console.log('this.contain.component', this.contain.component);
						document.title = '蓝图编辑器-' + data.visual.title;
						loading.close();
					})
					.catch(err => {
						console.log(err);
					});
			}
		},
		// 逻辑节点渲染
		handleLogicNode(item) {
			const that = this;
			if (item.disabled) {
				this.$message.warning('此功能暂未开发完成,敬请期待！');
				return false;
			}
			let nodeInfo = renderLogicNodeGraph(item);
			that.graph.addNode(nodeInfo);
		},
		// 事件渲染
		handleEvent(item) {
			return item && item.length > 0
				? item.map((event, index) => {
						return {
							id: 'outPort' + (index + 1),
							group: 'out',
							args: {
								x: '100%',
								y: 40 + (index + 1) * 25
							},
							attrs: { text: { fontSize: 10, fill: '#c0c6d6', text: event } }
						};
				  })
				: [];
		},
		// 动作渲染
		handleAction(item, eventLength) {
			return item && item.length > 0
				? item.map((event, index) => {
						return {
							id: 'inPort' + (index + 4),
							group: 'in',
							args: {
								x: '0%',
								y: 140 + eventLength * 25 + (index + 1) * 25
							},
							attrs: {
								text: {
									fontSize: 10,
									fill: '#c0c6d6',
									text: event.actionName
								}
							},
							label: {
								position: {
									name: 'right', // 标签位置计算方法的名称
									args: {} // 标签位置计算方法的参数
								}
							}
						};
				  })
				: [];
		},
		handleSetActive(item) {
			const that = this;
			if (item.isClick) {
				return false;
			}
			that.$set(item, 'isClick', true);
			let eventItems = that.handleEvent(item.eventNames);
			console.log('eventItems', eventItems);
			let outItems = [
				// {
				// 	id: 'outPort' + 1,
				// 	group: 'out',
				// 	args: {
				// 		x: '100%',
				// 		y: 65
				// 	},
				// 	attrs: {
				// 		text: {
				// 			fontSize: 10,
				// 			fill: '#c0c6d6',
				// 			text: '接口请求完成时'
				// 		}
				// 	}
				// },
				// {
				// 	id: 'outPort' + 2,
				// 	group: 'out',
				// 	args: {
				// 		x: '100%',
				// 		y: 90
				// 	},
				// 	attrs: {
				// 		text: {
				// 			fontSize: 10,
				// 			fill: '#c0c6d6',
				// 			text: '接口请求失败时'
				// 		}
				// 	}
				// },
				...eventItems
			];

			let actionItems = that.handleAction(item.actionConfig, outItems.length);
			let inItems = [
				{
					id: 'inPort' + 1,
					group: 'in',
					args: {
						x: '0%',
						y: 75 + outItems.length * 25 + 15
					},
					attrs: {
						text: {
							fontSize: 10,
							fill: '#c0c6d6',
							text: '显示'
						}
					},
					label: {
						position: {
							name: 'right', // 标签位置计算方法的名称
							args: {} // 标签位置计算方法的参数
						}
					}
				},
				{
					id: 'inPort' + 2,
					group: 'in',
					args: {
						x: '0%',
						y: 75 + outItems.length * 25 + 40
					},
					attrs: {
						text: {
							fontSize: 10,
							fill: '#c0c6d6',
							text: '隐藏'
						}
					},
					label: {
						position: {
							name: 'right', // 标签位置计算方法的名称
							args: {} // 标签位置计算方法的参数
						}
					}
				},
				{
					id: 'inPort' + 3,
					group: 'in',
					args: {
						x: '0%',
						y: 75 + outItems.length * 25 + 65
					},
					attrs: {
						text: {
							fontSize: 10,
							fill: '#c0c6d6',
							text: '请求数据'
						}
					},
					label: {
						position: {
							name: 'right', // 标签位置计算方法的名称
							args: {} // 标签位置计算方法的参数
						}
					}
				},
				...actionItems
			];

			let customDom = that.renderCustomDom(item, outItems.length, 1);
			that.target = that.graph.addNode({
				shape: 'html',
				index: item.index,
				x: 400,
				y: 200,
				width: 180,
				height: 25 * (inItems.length + outItems.length + 3),
				attrs: {
					body: {
						fill: '#1d2027'
						// stroke: "#d9d9d9",
						// strokeWidth: 1
					},
					compId: item.index
				},
				ports: {
					groups: {
						// 输入链接桩群组定义
						in: {
							position: 'left',
							attrs: {
								circle: {
									r: 4,
									magnet: true,
									stroke: '#fff',
									strokeWidth: 2,
									fill: '#44474c'
								}
							},
							position: {
								name: 'absolute'
							}
						},
						// 输出链接桩群组定义
						out: {
							label: {
								position: {
									name: 'left'
								}
							},
							attrs: {
								circle: {
									r: 4,
									magnet: true,
									stroke: '#fff',
									strokeWidth: 2,
									fill: '#44474c'
								}
							},
							position: {
								name: 'absolute'
							}
						}
					},
					items: inItems.concat(outItems)
				},
				eventConfig: item.eventConfig,

				html: customDom
			});

			that.mouseenterEdge();
			that.mouseenterNode();
		},
		//  自定义节点函数
		renderCustomDom(item, length, nodeType = 1) {
			let { name, icon, index } = item;

			console.log('item', item);
			let eventDom = `<div style="font-size:10px;width:100%;border:1px solid #1d2027;padding-left:10px;box-sizing:border-box;line-height:23px;color:#fff;background:#252c34">
                事件
            </div>`;

			let actionDom = `<div style="font-size:10px;margin-top:${length * 25}px;
            width:100%;border:1px solid #1d2027;padding-left:10px;box-sizing:border-box;line-height:23px;color:#fff;background:#252c34">
                动作
            </div>`;
			let titleBgColor = '#252c34';
			switch (nodeType) {
				case 1:
					titleBgColor = '#252c34';
					break;
				case 2:
					titleBgColor = '#0d5eff';
					break;
				case 3:
					titleBgColor = '#0d5eff';
					break;
				case 4:
					titleBgColor = '#139b00';
					break;
				case 5:
					titleBgColor = '#6d4eff';
					break;
				default:
					break;
			}

			let titleDom = `<div style="font-size:12px;font-weight:bold;width:100%;border:1px solid #1d2027;padding-left:10px;text-overflow:ellipsis;box-sizing:border-box;overflow:hidden;white-space:nowrap;line-height:23px;color:#fff;background:${titleBgColor}">
                <i class="iconfont ${item.icon}"></i>
                <span style="margin-left:3px;">${name}-${index.slice(0, 6)}</span>
                </div>
                `;

			let customDom = `${titleDom}
            ${nodeType == 1 ? eventDom : ''}
            ${nodeType == 1 ? actionDom : ''}`;

			return customDom;
		},
		saveJson() {
			// let nowData = this.graph.toJSON();
			// let model = {
			//     nodes: nowData.cells
			//         .filter((c) => c.shape !== "edge")
			//         .map((c) => {
			//             return {
			//                 id: c.id,
			//                 size: {
			//                     width: 100,
			//                     height: 50
			//                 },
			//                 ...c
			//             };
			//         }),
			//     edges: nowData.cells
			//         .filter((c) => c.shape == "edge")
			//         .map((c) => {
			//             return {
			//                 ...c,
			//                 source: c.source.cell,
			//                 target: c.target.cell
			//             };
			//         })
			// };
			// const gridLayout = new GridLayout({
			//     type: "dagre",
			//     rankdir: "LR",
			//     align: "UL",
			//     ranksep: 0,
			//     nodesep: 0,
			//     controlPoints: true
			// });
			// const newModel = gridLayout.layout(model);
			// this.graph.fromJSON(newModel);
			const loading = this.$loading({
				lock: true,
				text: '正在保存中，请稍后',
				spinner: 'el-icon-loading',
				background: 'rgba(0, 0, 0, 0.7)'
			});
			let newData = this.graph.toJSON();
			localStorage.setItem('dvp-lt-json', JSON.stringify(newData));
			loading.close();
			console.log('newData', newData);

			// 处理保存逻辑数据，转换成组件的eventConfig属性

			let edgeType = newData.cells.filter(d => d.shape == 'edge');
			edgeType.map(edge => {
				console.log('edge', edge);
			});
		},
		renderJson(data) {
			const that = this;
			let result = JSON.parse(data || '{}');
			that.graph.fromJSON(result);

			that.mouseenterEdge();
			that.mouseenterNode();
		},
		mouseenterNode() {
			const that = this;
			that.graph.on('node:mouseenter', ({ node }) => {
				node.addTools([
					{
						name: 'boundary',
						args: {
							attrs: {
								// fill: "#7c68fc",
								stroke: '#0d5eff',
								strokeWidth: 1,
								fillOpacity: 0.2
							}
						}
					},
					{
						name: 'button-remove',
						args: {
							x: 0,
							y: 0,
							offset: { x: 8, y: 0 }
						}
					}
				]);
			});
			that.graph.on('node:mouseleave', ({ node }) => {
				node.removeTools();
			});
		},
		mouseenterEdge() {
			const that = this;
			that.graph.on('edge:mouseenter', ({ edge }) => {
				edge.addTools([
					'source-arrowhead',
					'target-arrowhead',
					{
						name: 'button-remove',
						args: {
							distance: -30
						}
					}
				]);
			});
			that.graph.on('edge:mouseleave', ({ edge }) => {
				edge.removeTools();
			});
		},
		changeZoom() {
			this.graph.zoomTo(this.scale);
		},
		clearJson() {
			localStorage.removeItem('dvp-lt-json');
			this.graph.fromJSON({});
			// this.graph.centerContent();
		},
		handleBuild() {
			let newRouteUrl = this.$route.fullPath.replace(/^\/bluePrint/, '/build');
			this.$router.push(newRouteUrl);
		},
		handleMouseover(item) {
			this.$set(this.contain, 'overactive', item.index);
			// console.log('item', item);
		},
		handleMouseout() {
			this.$set(this.contain, 'overactive', undefined);
		}
	}
};
</script>

<style lang="scss" scoped>
.bluePrint {
	width: 100vw;
	height: 100vh;
	.head {
		height: 40px;
		display: flex;
		justify-content: space-between;
		align-items: center;
		user-select: none;
		background: #1d1e1f;
		&_compList {
			padding: 0 8px;
			box-sizing: border-box;
			width: 180px;
			display: flex;
			align-items: center;
			height: 40px;
			.head_btn {
				width: 40px;
				height: 24px;
				line-height: 26px;
				text-align: center;
				cursor: pointer;
				background: #303640;
				transition: 0.2s;
				i {
					color: #fff;
				}
			}
		}

		&_blueInfo {
			flex: 1;
			cursor: default;
			color: #fff;
			line-height: 40px;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
			display: flex;
			align-items: center;
			justify-content: center;
			.head_btn {
				width: 40px;
				height: 24px;
				line-height: 26px;
				text-align: center;
				cursor: pointer;
				background: #303640;
				transition: 0.2s;
				i {
					color: #fff;
				}
			}
		}
	}
	.wrap {
		height: calc(100vh - 40px);
		display: flex;
		justify-content: flex-start;
		.compList {
			color: #fff;
			width: 180px;
			min-width: 180px;
			background: #1d1f26;
			border-right: 1px solid #111317;
			.title {
				font-size: 14px;
				height: 38px;
				line-height: 38px;
				background: #262c33;
				border-top: 1px solid #111317;
				border-bottom: 1px solid #111317;
				padding-left: 10px;
			}
			.layerMenu {
				width: 100%;
				height: 100%;
				overflow: hidden;
				overflow-y: auto;
				.menu__item {
					margin-bottom: 1px;
					width: 100%;
					box-sizing: border-box;
					display: flex;
					align-items: center;
					height: 48px;
					padding: 0 6px;
					position: relative;
					background: #262c33;
					cursor: pointer;
					flex: none;
					font-size: 12px;
					.menu__icon {
						color: #409eff;
						margin-right: 10px;
						min-width: 53px;
						width: 53px;
						height: 30px;
						line-height: 30px;
						text-align: center;
						display: block;
						border: 1px solid #3a4659;
						background: #282a30;
					}
					.menu__name {
						display: -webkit-box;
						-webkit-box-orient: vertical;
						overflow: hidden;
						-webkit-line-clamp: 2;
					}
					.layer-thumbail-item {
						position: absolute;
						top: 5px;
						right: 5px;
						.lockIcon {
							margin-left: 5px;
						}
					}

					&.is-over,
					&:hover {
						color: #fff;
						background: rgba(143, 225, 255, 0.1);
						cursor: pointer;
					}
					&.is-click {
						cursor: not-allowed;
						background: #3a4659;
						color: #ccc;
					}
					&.ghost {
						opacity: 0.6;
						color: #fff;
						background: #409eff !important;
						cursor: move;
					}
					&.is-active {
						background: #409eff !important;
						color: #fff !important;
					}
					&.is-text {
						height: 32px;
					}
				}
			}
		}
		.logicNode {
			.content {
				padding: 0 10px;
				background: #13161a;
				.subTitle {
					font-size: 14px;
					height: 48px;
					line-height: 48px;
					background: #13161a;
					padding-left: 10px;
				}
				.menu__item {
					margin: 6px 0;
					width: 100%;
					box-sizing: border-box;
					display: flex;
					align-items: center;
					height: 36px;
					padding: 0 6px;
					position: relative;
					border-radius: 10px;
					cursor: pointer;
					flex: none;
					font-size: 12px;
					&.disabled {
						cursor: not-allowed;
						background-color: #fff !important;
						color: #c0c4cc !important;
						.menu__icon {
							color: #c0c4cc;
						}
					}
					&.orange {
						background: #ff700b;
					}
					&.blue {
						background: #0d5eff;
					}
					&.green {
						background: #139b00;
					}
					&.purple {
						background: #6d4eff;
					}
					.menu__icon {
						color: #fff;
						width: 30px;
						height: 30px;
						border-radius: 50%;
						line-height: 30px;
						text-align: center;
						display: block;
					}
				}
			}
		}
		.graph {
			flex: 1;
			position: relative;
			.title {
				height: 38px;
				line-height: 38px;
				padding: 0 20px;
				display: flex;
				justify-content: flex-end;
				align-items: center;
				background: #262c33;
				border-top: 1px solid #111317;
				border-bottom: 1px solid #111317;
				border-right: 1px solid #111317;
				span {
					width: 100px;
					color: #fff;
				}
				.el-slider {
					width: 300px;
				}
			}
			#container {
				// height: calc(100vh - 250px);
			}
			#miniMap {
				background: #409eff;
				position: absolute;
				bottom: 0;
				right: 0;
			}
		}
		.configLayer {
			color: #fff;
			width: 400px;
			min-width: 400px;
			background: #303133;
			.title {
				font-size: 14px;
				height: 38px;
				line-height: 38px;
				background: #262c33;
				border-top: 1px solid #111317;
				border-bottom: 1px solid #111317;
				padding-left: 10px;
			}
			.content {
				padding: 5px;
				box-sizing: border-box;
				.item {
					margin: 5px 0;
					font-size: 14px;
					font-weight: bold;
				}
			}
		}
	}
}
</style>
<style lang="scss">
.x6-widget-minimap {
	background-color: #1d2126;
}
.x6-widget-minimap-viewport {
	border: 2px solid #0d5eff;
}
</style>
